package com.flashflexpro.flexdirector.agent.console{
    import com.flashflexpro.flexdirector.agent.FlexDirectorAgent;
    import com.flashflexpro.flexdirector.conn.ConnWithSocket;
    import com.flashflexpro.flexdirector.conn.RemoteCallingEvent;
    import com.flashflexpro.flexdirector.model.ClassDesc;

    import flash.events.Event;
    import flash.net.Socket;
    import flash.system.Security;
    import flash.utils.Dictionary;
    import flash.utils.getDefinitionByName;
    import flash.utils.getQualifiedClassName;
    import flash.utils.getQualifiedSuperclassName;

    import mx.automation.Automation;
    import mx.collections.ArrayCollection;
    import mx.managers.SystemManager;
    import mx.core.mx_internal;

    use namespace mx_internal;

    public class ConnectionToConsole extends ConnWithSocket implements IDirectorAgent{
        public function ConnectionToConsole( ui:SystemManager ){
            super( new Socket(), ui );
        }

        public function get sysManager():SystemManager{
            return _ui as SystemManager;
        }

        public function connectTo( appInstId:String, address:String = "127.0.0.1", port:int = 9696 ):void{
            Security.loadPolicyFile( "xmlsocket://" + address + ":" + port );
            _address = address;
            _port = port;
            _connectionId = appInstId;

            _socket.addEventListener( Event.CONNECT, onConnect );
            _socket.connect( address, port );
        }


        protected var _port:int;
        protected var _address:String;


        public function get address():String{
            return _address;
        }

        public function get port():int{
            return _port;
        }

        private function onConnect( event:Event ):void{
            _dic = new Dictionary( false );
            for( var o:* in Automation.delegateDictionary ){
                var c:Class = o as Class;
                var currentClassName:String = getQualifiedClassName( c );
                if( _dic[ currentClassName ] == null ){
                    putSuperClassesIntoTree( currentClassName );
                }
            }

            var mainClassName:String = sysManager.info()[ "mainClassName" ];
            var mainSuperClassNames:Array = [ mainClassName ].concat( Console.getSuperClassNames( getDefinitionByName( mainClassName ) ) );

            var classDefinitionTree:ClassDesc = _dic[ "Object" ];

            //socket connect but doesn't mean agent it's connencted, until appInstId got accepted.
            callPeer( RemoteCallingEvent.CONNECTED, _connectionId, FlexDirectorAgent.getBuildInfo(), classDefinitionTree,
                    sysManager.loaderInfo.url, mainSuperClassNames );
            _dic = null;
        }

        private var _dic:Dictionary;

        private function putSuperClassesIntoTree( currentClassName:String ):ClassDesc{
            var currentDesc:ClassDesc = new ClassDesc();
            currentDesc.className = currentClassName;
            _dic[ currentClassName ] = currentDesc;
            if( currentClassName != "Object" ){
                var superClassName:String = getQualifiedSuperclassName( getDefinitionByName( currentClassName ) );
                var superClassDesc:ClassDesc = _dic[ superClassName ];
                if( superClassDesc == null ){
                    superClassDesc = putSuperClassesIntoTree( superClassName );
                }
                currentDesc.parent = superClassDesc;

                if( superClassDesc.children.length > 0 ){
                    insertIntoList( currentDesc, superClassDesc.children );
                }
                else{
                    superClassDesc.children.addItem( currentDesc );
                }
            }
            return currentDesc;
        }

        private function insertIntoList( insert:ClassDesc, list:ArrayCollection ):void{
            var len:int = list.length;
            for( var i:int = 0; i < len; i++ ){
                var listElement:ClassDesc = list.getItemAt( i ) as ClassDesc;
                if( insert.className < listElement.className ){
                    list.addItemAt( insert, i );
                    return;
                }
            }
            list.addItemAt( insert, len );
        }

    }
}